package com.yy.crypto.advice;

import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yy.crypto.annotation.EncryptionAnnotation;
import com.yy.crypto.common.entity.DResult;
import com.yy.crypto.entity.RequestBase;
import com.yy.crypto.util.AESUtil;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import com.yy.crypto.common.exception.CryptoException;

import java.lang.reflect.Type;

/**
 * @author yanglin
 * @description: responseBody自动解密
 * @email yling_dream@163.com
 * @date : Created in 2022/2/4 15:12
 */
@ControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<DResult<?>> {

    /**
     * ResponseBodyAdvice是对请求相应的json传进行处理，一般用于相应结果的加密
     */
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        // ParameterizedTypeImpl genericParameterType = (ParameterizedTypeImpl) returnType.getGenericParameterType();
        Type type = returnType.getGenericParameterType();
        // 如果直接是Result并且有解密注解，则处理
        if (type == DResult.class && returnType.hasMethodAnnotation(EncryptionAnnotation.class)) {
            return true;
        }
        // 如果不是ResponseBody或者是Result，则放行
        if (type != ResponseEntity.class) {
            return false;
        }
        // 如果是ResponseEntity<Result>并且有解密注解，则处理
        //for (Type type : genericParameterType.getActualTypeArguments()) {
        //    if (((ParameterizedTypeImpl) type).getRawType() == DResult.class && returnType.hasMethodAnnotation(EncryptionAnnotation.class)) {
        //        return true;
        //    }
        //}
        return false;
    }

    @SneakyThrows
    @Override
    public DResult<?> beforeBodyWrite(DResult<?> body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        // 真实数据
        Object data = body.getData();
        // 如果data为空，直接返回
        if (data == null) {
            return body;
        }
        // 如果是实体，并且继承了Request，则放入时间戳
        if (data instanceof RequestBase) {
            ((RequestBase) data).setCurrentTimeMillis(System.currentTimeMillis());
        }
        String dataText = JSONUtil.toJsonStr(data);
        // 如果data为空，直接返回
        if (StringUtils.isBlank(dataText)) {
            return body;
        }
        // 如果位数小于16，报错
        if (dataText.length() < 16) {
            throw new CryptoException("加密失败，数据小于16位");
        }
        String encryptText = AESUtil.encryptHex(dataText);
        return DResult.of(encryptText, body.getCode(), body.getMsg());
    }
}
